package de.bazinga.rotw.map;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Hashtable;
import java.util.Vector;

import javax.swing.ImageIcon;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.light.PointLight;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Node;
import com.jme.scene.Skybox;
import com.jme.scene.Spatial.NormalsMode;
import com.jme.scene.shape.Box;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.FogState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;
import com.jmex.game.state.GameStateManager;
import com.jmex.jbullet.PhysicsSpace;
import com.jmex.jbullet.collision.shapes.CollisionShape;
import com.jmex.jbullet.collision.shapes.MeshCollisionShape;
import com.jmex.jbullet.nodes.PhysicsNode;
import com.jmex.terrain.TerrainBlock;
import com.jmex.terrain.util.ImageBasedHeightMap;
import com.jmex.terrain.util.ProceduralSplatTextureGenerator;

import de.bazinga.rotw.base.Flag;
import de.bazinga.rotw.collision.CollidableObjects;
import de.bazinga.rotw.effects.LensFlareEffects;
import de.bazinga.rotw.game.Game;
import de.bazinga.rotw.game.RotwGameState;
import de.bazinga.rotw.gameModes.CaptureTheZombie;
import de.bazinga.rotw.gameModes.Deathmatch;
import de.bazinga.rotw.gameModes.DefendYourBase;
import de.bazinga.rotw.gameModes.TeamDeathmatch;
import de.bazinga.rotw.gameModes.TreasureHunt;
import de.bazinga.rotw.model.Model;
import de.bazinga.rotw.model.ModelCache;
import de.bazinga.rotw.objects.AmmoStation;
import de.bazinga.rotw.objects.ArmorStation;
import de.bazinga.rotw.objects.BeamStation;
import de.bazinga.rotw.objects.Button;
import de.bazinga.rotw.objects.DoubleDamageItem;
import de.bazinga.rotw.objects.HEGrenadeItem;
import de.bazinga.rotw.objects.HealthStation;
import de.bazinga.rotw.objects.JumpStation;
import de.bazinga.rotw.objects.RifleGunItem;
import de.bazinga.rotw.objects.SmokeGrenadeItem;
import de.bazinga.rotw.objects.Stair;
import de.bazinga.rotw.objects.TwoButtons;
import de.bazinga.rotw.objects.UziItem;
import de.bazinga.rotw.objects.elevator.Elevator;
import de.bazinga.rotw.player.Player;
import de.bazinga.rotw.sky.Sky;
import de.bazinga.rotw.texture.TextureCache;
import de.bazinga.rotw.treasure.Treasure;
import de.bazinga.rotw.vehicle.CabrioCar;
import de.bazinga.rotw.vehicle.MilitaryCar;
import de.bazinga.rotw.vehicle.RaceCar;
import de.bazinga.rotw.zombie.Waypoint;

public class MapLoader {
	
	public static Document loadXMLDocument(File xmlFile) {
		// Load XML
		try{
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();

			final Document document = builder.parse(xmlFile);
			
			return document;
		}catch(Exception e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	public static void loadMap(Node rootNode, String mapPath, Player player) throws Exception {
		RotwGameState gameState = (RotwGameState)GameStateManager.getInstance().getChild("gameState");
		
		/**
		 * Load playerPositions
		 */
		loadPlayerPositions(rootNode, mapPath, player);
		
		
		/**
		 * Load Light/Lensflare
		 */
		loadLight(rootNode, mapPath, player);
		
		/**
		 * Load Fog
		 */
		loadFog(rootNode, mapPath, player);
		
		/**
		 * Load Skybox
		 */
		loadSkyBox(rootNode, mapPath);
		
		/**
		 * Load Ground
		 */
		loadGround(rootNode, mapPath, player);
		
		/**
		 * Load wall
		 */
		loadWalls(rootNode, mapPath, player);
		
		/**
		 * LOAD TERRAIN
		 */
		loadTerrain(rootNode, mapPath, player);
		
		/**
		 * Load Stairs
		 */
		loadStairs(rootNode, mapPath, player);
		
		/**
		 * Load items
		 */
		loadItems(rootNode, mapPath, player);
		
		/**
		 * Load Buttons
		 */
		loadButtons(rootNode, mapPath, player);
		
		/**
		 * Load elevators
		 */
		loadElevator(rootNode, mapPath, player);
		
		/**
		 * Load Objects
		 */
		loadObjects(rootNode, mapPath, player);
		
		/**
		 * Load Zombie-Waypoints
		 */
		if(gameState.getGameMode() instanceof CaptureTheZombie) {
			loadZombieWaypoints(rootNode, mapPath, player);
		}
		
		/**
		 * Load Vehicles
		 */
		loadVehicles(rootNode, mapPath, player);
	}
	
	
	
	
	private static void loadPlayerPositions(Node rootNode, String mapPath, Player player) throws Exception {
		/**
		 * Load playerPositions
		 */
		File infoFile = new File(mapPath+"/levelInfo.xml");
		if(infoFile.exists()) {			
			Document doc = loadXMLDocument(infoFile);
			
			// Weapons
			((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setDefaultWeapons(
					doc.getElementsByTagName("weapons").item(0).getFirstChild().getNodeValue().split(","));
			
			
			// GameMode
			String gameMode = doc.getElementsByTagName("mode").item(0).getFirstChild().getNodeValue().toLowerCase();
			if(gameMode.equals("deathmatch")) {
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setGameMode(
						new Deathmatch());
			}else if(gameMode.equals("teamdeathmatch")) {
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setGameMode(
						new TeamDeathmatch());
			}else if(gameMode.equals("capturethezombie")) {
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setGameMode(
						new CaptureTheZombie());
			}else if(gameMode.equals("defendourbase")) {
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setGameMode(
						new DefendYourBase());
			}else if(gameMode.equals("treasurehunt")) {
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setGameMode(
						new TreasureHunt());
			}
			
			
			// Bloom
			if(doc.getElementsByTagName("useBloom").item(0).getFirstChild().getNodeValue().toLowerCase().equals("true")) {
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getBloomRenderPass().setUseCurrentScene(true);
			}
			((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getBloomRenderPass()
				.setBlurIntensityMultiplier(
						Float.valueOf(doc.getElementsByTagName("blurIntensity").item(0).getFirstChild().getNodeValue()));
			((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getBloomRenderPass()
			.setExposurePow(
					Float.valueOf(doc.getElementsByTagName("exposurePow").item(0).getFirstChild().getNodeValue()));
		
			
			
			
			// Water
			if(doc.getElementsByTagName("waterEnabled").item(0).getFirstChild().getNodeValue().toLowerCase().equals("true")) {
				
				float waterHeight = Float.valueOf(doc.getElementsByTagName("waterHeight").item(0).getFirstChild().getNodeValue());
				float waveMaxHeight = Float.valueOf(doc.getElementsByTagName("waveMaxHeight").item(0).getFirstChild().getNodeValue());
				float waveMinHeight = Float.valueOf(doc.getElementsByTagName("waveMinHeight").item(0).getFirstChild().getNodeValue());
				
				((RotwGameState)GameStateManager.getInstance().getChild("gameState"))
					.resetWaterEffects(waterHeight, waveMaxHeight, waveMinHeight);
				
			}else{
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).resetWaterEffects();
			}
			
			
			NodeList startPoints = doc.getElementsByTagName("start");
			
			Hashtable<Integer,Vector<Vector3f>> startPos = new Hashtable<Integer,Vector<Vector3f>>();
			
			startPos.put(1, new Vector<Vector3f>());
			startPos.put(2, new Vector<Vector3f>());
			
			for(int i=0;i < startPoints.getLength(); i++) {
				 Vector3f startVec = readVector3f(startPoints.item(i).getChildNodes());
				 
				 int team = Integer.parseInt(startPoints.item(i).getChildNodes().item(7).getFirstChild().getNodeValue());
				 
				 startPos.get(team).add(startVec);
			}
			
			player.setStartPosition(startPos);
			player.setToStart();
			
			
			if("treasurehunt".equals(gameMode)) {
				NodeList treasures = doc.getElementsByTagName("treasure");
				
				Vector<Treasure> treasureList = new Vector<Treasure>();
				
				for(int i=0;i < treasures.getLength(); i++) {
					 Vector3f treasureVec = readVector3f(treasures.item(i).getChildNodes());
					 
					 Treasure t = new Treasure(treasureList.size());
					 t.setLocalTranslation(treasureVec);
					 t.updateRenderState();
					 rootNode.attachChild(t);
					 
					 treasureList.add(t);
				}
				
				RotwGameState gameState = (RotwGameState)GameStateManager.getInstance().getChild("gameState");
				TreasureHunt th = (TreasureHunt)gameState.getGameMode();
				
				th.setTreasureList(treasureList);
			}
			
			if(gameMode.equals("defendourbase")) {
				RotwGameState gameState = (RotwGameState)GameStateManager.getInstance().getChild("gameState");
				DefendYourBase dyb = (DefendYourBase)gameState.getGameMode();
				
				// Get Flag location
				Vector3f baseLocation = readVector3f(doc.getElementsByTagName("baseLocation").item(0).getChildNodes());
				
				Flag test = new Flag();
				test.setLocalTranslation(baseLocation);
				test.setLocalScale(0.2f);
				test.updateRenderState();
				rootNode.attachChild(test);
				
				dyb.setBaseStation(test);
				
				
				
				Vector<Vector3f> attStartLocation = 
					dyb.getBaseAttackerStartLocations();
				attStartLocation.clear();
				
				NodeList locs = doc.getElementsByTagName("attLocation");
				for(int i=0;i < locs.getLength(); i++) {
					 Vector3f startVec = readVector3f(locs.item(i).getChildNodes());
					 attStartLocation.add(startVec);
				}
			}else{
				//((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setBaseStation(null);
			}
		}
	}
	
	
	private static void loadLight(Node rootNode, String mapPath, Player player) throws Exception {
		// LensFlare
		// Set Light
		LightState lightState = Game.getGame().getDisplay().getRenderer().createLightState();
		lightState.detachAll();

		/**
		 * Load Light
		 */
		File lightFile = new File(mapPath+"/light.xml");
		if(lightFile.exists()) {
			Document doc = loadXMLDocument(lightFile);
			
			// LensFlareEffect
			NodeList lensFlareLocation = doc.getElementsByTagName("LensFlareEffect").item(0).getChildNodes();
			Vector3f location = readVector3f(lensFlareLocation);
			
			new LensFlareEffects(lightState,rootNode,location);
			
			
			
			// Lights
			NodeList lights = doc.getElementsByTagName("light");
			for(int i=0;i < lights.getLength(); i++) {
				NodeList singleLight = lights.item(i).getChildNodes();
				
				location = readVector3f(singleLight);
				
				PointLight light = createLight(location);
				if(i == 0) light.setShadowCaster(true);
				
				lightState.attach(light);
			}
			
			lightState.get(0).setShadowCaster(true);
		}

		rootNode.setRenderState(lightState);
		rootNode.updateRenderState();
	}
	
	
	private static void loadFog(Node rootNode, String mapPath, Player player) throws Exception {
		File fogFile = new File(mapPath+"/fog.xml");
		if(fogFile.exists()) {
			Document doc = loadXMLDocument(fogFile);
			
			NodeList fogData = doc.getElementsByTagName("Fog").item(0).getChildNodes();
			
			ColorRGBA color = null;
			
			float density = Float.parseFloat(fogData.item(1).getFirstChild().getNodeValue());
			
			NodeList colorData = fogData.item(3).getChildNodes();
			float r,g,b,a;
			r = Float.parseFloat(colorData.item(1).getFirstChild().getNodeValue());
			g = Float.parseFloat(colorData.item(3).getFirstChild().getNodeValue());
			b = Float.parseFloat(colorData.item(5).getFirstChild().getNodeValue());
			a = Float.parseFloat(colorData.item(7).getFirstChild().getNodeValue());
				
			color = new ColorRGBA(r,g,b,a);
			
			float start = Float.parseFloat(fogData.item(5).getFirstChild().getNodeValue());
			float end = Float.parseFloat(fogData.item(7).getFirstChild().getNodeValue());
			
			String densityFunc = fogData.item(9).getFirstChild().getNodeValue();
			
			FogState fs = Game.getGame().getDisplay().getRenderer().createFogState();
			fs.setDensity(density);
			fs.setColor(color);
			fs.setEnd(end);
			fs.setStart(start);
			
			if(densityFunc.equals("exp")) {
				fs.setDensityFunction(FogState.DensityFunction.Exponential); //fs.setDensityFunction(FogState.DF_LINEAR); <- jME 1.0
			}else if(densityFunc.equals("linear")) {
				fs.setDensityFunction(FogState.DensityFunction.Linear); //fs.setDensityFunction(FogState.DF_LINEAR); <- jME 1.0
			}
			
			fs.setQuality(FogState.Quality.PerVertex); //fs.setApplyFunction(FogState.AF_PER_VERTEX); <- jME 1.0
			rootNode.setRenderState(fs);
		}
	}
	
	
	private static void loadSkyBox(Node rootNode, String mapPath) throws Exception {
		((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setSkybox(null);
		
		File skyboxFile = new File(mapPath+"/skybox.xml");
		if(skyboxFile.exists()) {
			Document doc = loadXMLDocument(skyboxFile);
			
			
			try {
				Skybox skybox = Sky.setupSky(
						new File(mapPath+doc.getElementsByTagName("north").item(0).getFirstChild().getNodeValue()).toURI().toURL(),
						new File(mapPath+doc.getElementsByTagName("west").item(0).getFirstChild().getNodeValue()).toURI().toURL(),
						new File(mapPath+doc.getElementsByTagName("south").item(0).getFirstChild().getNodeValue()).toURI().toURL(),
						new File(mapPath+doc.getElementsByTagName("east").item(0).getFirstChild().getNodeValue()).toURI().toURL(),
						new File(mapPath+doc.getElementsByTagName("top").item(0).getFirstChild().getNodeValue()).toURI().toURL(),
						new File(mapPath+doc.getElementsByTagName("bottom").item(0).getFirstChild().getNodeValue()).toURI().toURL()
					);
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setSkybox(skybox);
				rootNode.attachChild(skybox);
			} catch (MalformedURLException e) {}
		}
	}
	
	
	private static void loadGround(Node rootNode, String mapPath, Player player) throws Exception {
		File groundFile = new File(mapPath+"/ground.xml");
		if(groundFile.exists()) {
			Document doc = loadXMLDocument(groundFile);
			

			Node grounds = new Node("ground");
			Node groundsPortable = new Node("groundPortable");
			grounds.attachChild(groundsPortable);

			NodeList nodeList = doc.getElementsByTagName("ground");
			
			for(int i=0;i<nodeList.getLength();i++) {
				NodeList ground = nodeList.item(i).getChildNodes();
				
				String name = ground.item(1).getFirstChild().getNodeValue();
				
				
				Vector3f min = readVector3f(ground.item(3).getChildNodes());
				Vector3f max = readVector3f(ground.item(5).getChildNodes());
				
				
				String texture = ground.item(7).getFirstChild().getNodeValue();
				
				// TextureCoordinates
				float factorX = 5;
				float factorY = 5;
				
				
				try{
					NodeList texCoords = ground.item(9).getChildNodes();
					factorX = Float.parseFloat(texCoords.item(1).getFirstChild().getNodeValue());
					factorY = Float.parseFloat(texCoords.item(3).getFirstChild().getNodeValue());
				}catch(NullPointerException e) {}
				
				
				
				// Apply the data to a Ground-Box
				//Box groundBox = new Box(name,min,max);
				Vector3f extend = max.subtract(min).mult(0.5f);
				Box groundBox = new Box(name,Vector3f.ZERO,extend.x, extend.y, extend.z);
				
				CullState culling = Game.getGame().getDisplay().getRenderer().createCullState();
				culling.setCullFace(CullState.Face.Back);
				groundBox.setRenderState(culling);
				
				if(!texture.equals("")) {
					try {
						groundBox.setRenderState(TextureCache.getInstance().getTexture(new File(mapPath+"/"+texture).toURI().toURL()));
						groundBox.scaleTextureCoordinates(0, new Vector2f(factorX,factorY));
						groundBox.updateRenderState();
					} catch (MalformedURLException e) {}
				}
				
				groundBox.setModelBound(new BoundingBox());
				groundBox.updateModelBound();
				
		        
		        
				// Add Phyics (weight = 0, so it doesnt move)
		        PhysicsNode groundPhysicsNode = new PhysicsNode(groundBox,CollisionShape.ShapeTypes.BOX,0);
				groundPhysicsNode.setLocalTranslation(min.add(extend));
				
				if(ground.item(ground.getLength() - 2).getNodeName().equals("portable") && ground.item(ground.getLength() - 2).getFirstChild().getNodeValue().equals("true")) {
					// Portable
					groundsPortable.attachChild(groundPhysicsNode);
				}else{
					grounds.attachChild(groundPhysicsNode);
				}
				
				groundPhysicsNode.updateRenderState();
				// Add ground to physicsNode
		        //((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getPhyicsSpace().add(groundPhysicsNode);
				PhysicsSpace.getPhysicsSpace().add(groundPhysicsNode);
				
				CollidableObjects.getInstance().addObject("ground",groundPhysicsNode);
			}
			
			
			rootNode.attachChild(grounds);
			
			CollidableObjects.getInstance().addObject("groundPortableNode", groundsPortable);
			CollidableObjects.getInstance().addObject("groundNode", grounds);

	        

//	        PhysicsNode node2=new PhysicsNode(new Box("physicsobstaclemesh",Vector3f.ZERO,2,2,2),CollisionShape.ShapeTypes.BOX,0);
//	        node2.setLocalTranslation(new Vector3f(-10,15,-42f));
//	        rootNode.attachChild(node2);
//	        node2.updateRenderState();
//	        ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getPhyicsSpace().add(node2);
		}
	}
	
	
	private static void loadWalls(Node rootNode, String mapPath, Player player) throws Exception {

		File wallFile = new File(mapPath+"/wall.xml");
		if(wallFile.exists()) {
			Document doc = loadXMLDocument(wallFile);
			
			Node walls = new Node("walls");
			
			Node portalWalls = new Node("portalWalls");
			walls.attachChild(portalWalls);
			
			
			NodeList nodeList = doc.getElementsByTagName("wall");
			
			for(int i=0;i<nodeList.getLength();i++) {
				NodeList ground = nodeList.item(i).getChildNodes();
				
				String name = ground.item(1).getFirstChild().getNodeValue();
				
				
				Vector3f min = readVector3f(ground.item(3).getChildNodes());
				Vector3f max = readVector3f(ground.item(5).getChildNodes());
				
				
				String texture = ground.item(7).getFirstChild().getNodeValue();
				

				// TextureCoordinates
				float factorX = 1;
				float factorY = 1;
				
				
				try{
					NodeList texCoords = ground.item(9).getChildNodes();
					factorX = Float.parseFloat(texCoords.item(1).getFirstChild().getNodeValue());
					factorY = Float.parseFloat(texCoords.item(3).getFirstChild().getNodeValue());
				}catch(NullPointerException e) {}
				
				
				// Apply the data to a Wall-Box// Apply the data to a Ground-Box
				//Box groundBox = new Box(name,min,max);
				Vector3f extend = max.subtract(min).mult(0.5f);
				Box wallBox = new Box(name,Vector3f.ZERO,extend.x, extend.y, extend.z);
				
				CullState culling = Game.getGame().getDisplay().getRenderer().createCullState();
				culling.setCullFace(CullState.Face.Back);
				wallBox.setRenderState(culling);
				
				if(!texture.equals("")) {
					try {
						wallBox.setRenderState(TextureCache.getInstance().getTexture(new File(mapPath+"/"+texture).toURI().toURL()));
						wallBox.scaleTextureCoordinates(0, new Vector2f(factorX,factorY));
						wallBox.updateRenderState();
					} catch (MalformedURLException e) {}
				}				
				wallBox.setModelBound(new BoundingBox());
				wallBox.updateModelBound();
				
		        
		        
				// Add Phyics (weight = 0, so it doesnt move)
		        PhysicsNode wallPhysicsNode = new PhysicsNode(wallBox,CollisionShape.ShapeTypes.BOX,0);
		        wallPhysicsNode.setLocalTranslation(min.add(extend));
				

				if(ground.item(ground.getLength() - 2).getNodeName().equals("portable") && ground.item(ground.getLength() - 2).getFirstChild().getNodeValue().equals("true")) {
					// Portable
					portalWalls.attachChild(wallPhysicsNode);
				}else{
					walls.attachChild(wallPhysicsNode);
				}
				
				
				wallPhysicsNode.updateRenderState();
				// Add ground to physicsNode
		        //((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getPhyicsSpace().add(groundPhysicsNode);
				PhysicsSpace.getPhysicsSpace().add(wallPhysicsNode);
				
				
				CollidableObjects.getInstance().addObject("wall",wallPhysicsNode);
			}
			
			rootNode.attachChild(walls);
			CollidableObjects.getInstance().addObject("wallNode", walls);
			CollidableObjects.getInstance().addObject("portalWallNode", portalWalls);
		}
	}
	
	
	private static void loadTerrain(Node rootNode, String mapPath, Player player) throws Exception {
		File terrainFile = new File(mapPath+"/terrain.xml");
		if(terrainFile.exists()) {
			Document doc = loadXMLDocument(terrainFile);			
			
			
			NodeList data = doc.getElementsByTagName("terrain").item(0).getChildNodes();
			String heightMapImage = data.item(1).getFirstChild().getNodeValue();
			int size = Integer.valueOf(data.item(3).getFirstChild().getNodeValue());
			
			
			Vector3f terrainScale = readVector3f(data.item(5).getChildNodes());
			
			
			
			
			
			
			// Load Terrain
			URL img = null;
			try {
				img = new File(mapPath+"/"+heightMapImage).toURI().toURL();
			} catch (MalformedURLException e1) {
				e1.printStackTrace();
			}
			
			ImageBasedHeightMap heightMap = new ImageBasedHeightMap(new ImageIcon(img).getImage());

			TerrainBlock terrainBlock = new TerrainBlock("Terrain", heightMap.getSize(), terrainScale,
					heightMap.getHeightMap(), new Vector3f(0,0,0)/*new Vector3f(-terrainScale.getX()*heightMap.getSize()/2.0f, -63, -terrainScale.getZ()*heightMap.getSize()/2.0f)*/);
			terrainBlock.setNormalsMode(NormalsMode.AlwaysNormalize);
			
			terrainBlock.setModelBound(new BoundingBox());
			terrainBlock.updateModelBound();
			
			ProceduralSplatTextureGenerator pt = new ProceduralSplatTextureGenerator(heightMap);
			

			NodeList nodeList = doc.getElementsByTagName("texture");
			for(int i=0;i<nodeList.getLength();i++) {
				NodeList texture = nodeList.item(i).getChildNodes();
				
				String file = texture.item(1).getFirstChild().getNodeValue();
				int start = Integer.valueOf(texture.item(3).getFirstChild().getNodeValue());
				int max = Integer.valueOf(texture.item(5).getFirstChild().getNodeValue());
				int end = Integer.valueOf(texture.item(7).getFirstChild().getNodeValue());
				
				try {
					pt.addTexture(new ImageIcon(new File(mapPath+"/"+file).toURI().toURL()), start, max, end);
				} catch (MalformedURLException e) {
					e.printStackTrace();
				}
			}
			
			
			// Get SplatTextures
			NodeList nList = doc.getElementsByTagName("splat");
			for(int i=0;i<nList.getLength();i++) {
				NodeList splat = nList.item(i).getChildNodes();
				
				String map = splat.item(1).getFirstChild().getNodeValue();
				String texture = splat.item(3).getFirstChild().getNodeValue();
				
				try {
					pt.addSplatTexture(
							new ImageIcon(new File(mapPath+"/"+map).toURI().toURL()),
							new ImageIcon(new File(mapPath+"/"+texture).toURI().toURL()));
				} catch (MalformedURLException e) {
					e.printStackTrace();
				}
			}
			
			
			pt.createTexture(size);
			
			TextureState ts = Game.getGame().getDisplay().getRenderer().createTextureState();
			Texture t1 = TextureManager.loadTexture(pt.getImageIcon().getImage(),
								Texture.MinificationFilter.Trilinear, Texture.MagnificationFilter.Bilinear, true);
			ts.setTexture(t1, 0);
			terrainBlock.setRenderState(ts);
			
			
			MeshCollisionShape collisionShape=new MeshCollisionShape(terrainBlock);
			PhysicsNode terrainPhysicsNode=new PhysicsNode(terrainBlock, collisionShape,0);

			terrainPhysicsNode.setLocalTranslation(new Vector3f(-terrainScale.getX()*heightMap.getSize()/2.0f, -63, -terrainScale.getZ()*heightMap.getSize()/2.0f));
			terrainPhysicsNode.rotateUpTo(new Vector3f(0,1,0));
			PhysicsSpace.getPhysicsSpace().add(terrainPhysicsNode);

			
			rootNode.attachChild(terrainPhysicsNode);
	        

			((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setTerrainPhysicsNode(terrainPhysicsNode);
			((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setTerrainBlock(terrainBlock);
		}else{
			((RotwGameState)GameStateManager.getInstance().getChild("gameState")).setTerrainBlock(null);
		}
	}
	
	
	private static void loadStairs(Node rootNode, String mapPath, Player player) throws Exception {
		File stairsFile = new File(mapPath+"/stairs.xml");
		if(stairsFile.exists()) {
			Document doc = loadXMLDocument(stairsFile);
			
			NodeList stairs = doc.getElementsByTagName("stair");
			for(int i=0;i < stairs.getLength(); i++) {
				NodeList s = stairs.item(i).getChildNodes();
				
				
				Vector3f start = readVector3f(s.item(1).getChildNodes());
				Vector3f end = readVector3f(s.item(3).getChildNodes());
				

				int steps = Integer.parseInt(s.item(5).getFirstChild().getNodeValue());
				String texture = s.item(7).getFirstChild().getNodeValue();
				String flag = s.item(9).getFirstChild().getNodeValue();
				
				int dirFlag = 0;
				if(flag.equals("XUP")) dirFlag = Stair.XDIRECTIONUP;
				else if(flag.equals("XDOWN")) dirFlag = Stair.XDIRECTIONDOWN;
				else if(flag.equals("ZUP")) dirFlag = Stair.ZDIRECTIONUP;
				else dirFlag = Stair.ZDIRECTIONDOWN;
				
				try {
					Stair stair = new Stair(start, end, steps,new File(mapPath+"/"+texture).toURI().toURL(), dirFlag);
					rootNode.attachChild(stair);
				} catch (MalformedURLException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	
	private static void loadItems(Node rootNode, String mapPath, Player player) throws Exception {
		File itemFile = new File(mapPath+"/items.xml");
		if(itemFile.exists()) {
			Document doc = loadXMLDocument(itemFile);
			
			NodeList nodeList = doc.getElementsByTagName("item");
			
			for(int i=0;i<nodeList.getLength();i++) {
				NodeList item = nodeList.item(i).getChildNodes();
				
				String type = item.item(1).getFirstChild().getNodeValue();
				
				Vector3f min = readVector3f(item.item(3).getChildNodes());
				Vector3f max = readVector3f(item.item(5).getChildNodes());
				
				
				
				
				// Apply the data
				if(type.equals("health")) {
					HealthStation health = new HealthStation(min,max);
					rootNode.attachChild(health);
					CollidableObjects.getInstance().addObject("gameObjects", health);
				}else if(type.equals("armor")) {
					ArmorStation armor = new ArmorStation(min,max);
					rootNode.attachChild(armor);
					CollidableObjects.getInstance().addObject("gameObjects", armor);
				}else if(type.equals("ammo")) {
					AmmoStation ammo = new AmmoStation(min,max);
					rootNode.attachChild(ammo);
					CollidableObjects.getInstance().addObject("gameObjects", ammo);
				}else if(type.equals("jumper")) {
					JumpStation jumper = new JumpStation(min,max);
					rootNode.attachChild(jumper);
					CollidableObjects.getInstance().addObject("gameObjects", jumper);
				}else if(type.equals("beam")) {
					BeamStation beamer = new BeamStation(min,max);
					rootNode.attachChild(beamer);
					CollidableObjects.getInstance().addObject("gameObjects", beamer);
				}else if(type.equals("rifle")) {
					RifleGunItem rifleItem = new RifleGunItem(min,max);
					rootNode.attachChild(rifleItem);
					CollidableObjects.getInstance().addObject("gameObjects", rifleItem);
				}else if(type.equals("uzi")) {
					UziItem uziItem = new UziItem(min,max);
					rootNode.attachChild(uziItem);
					CollidableObjects.getInstance().addObject("gameObjects", uziItem);
				}else if(type.equals("smokeGrenade")) {
					SmokeGrenadeItem smokeGrenadeItem = new SmokeGrenadeItem(min,max);
					rootNode.attachChild(smokeGrenadeItem);
					CollidableObjects.getInstance().addObject("gameObjects", smokeGrenadeItem);
				}else if(type.equals("heGrenade")) {
					HEGrenadeItem heGrenadeItem = new HEGrenadeItem(min,max);
					rootNode.attachChild(heGrenadeItem);
					CollidableObjects.getInstance().addObject("gameObjects", heGrenadeItem);
				}else if(type.equals("doubleDamage")) {
					DoubleDamageItem doubleDamageItem = new DoubleDamageItem(min,max);
					rootNode.attachChild(doubleDamageItem);
					CollidableObjects.getInstance().addObject("gameObjects", doubleDamageItem);
				}
			}
		}
	}
	
	
	private static void loadButtons(Node rootNode, String mapPath, Player player) throws Exception {
		File buttonFile = new File(mapPath+"/buttons.xml");
		if(buttonFile.exists()) {
			Document doc = loadXMLDocument(buttonFile);
			
			NodeList nodeList = doc.getElementsByTagName("Button");
			
			for(int i=0;i<nodeList.getLength();i++) {
				NodeList button = nodeList.item(i).getChildNodes();
				
				String buttonTexture = button.item(1).getFirstChild().getNodeValue();
				
				String wallTexture = button.item(3).getFirstChild().getNodeValue();

				int openDuration = Integer.valueOf(button.item(5).getFirstChild().getNodeValue());
				boolean hideOnCollision = (button.item(7).getFirstChild().getNodeValue().equals("true")) ? true:false;

				int team = Integer.valueOf(button.item(9).getFirstChild().getNodeValue());
				
				Vector3f buttonMin = readVector3f(button.item(11).getChildNodes());
				Vector3f buttonMax = readVector3f(button.item(13).getChildNodes());
				Vector3f wallMin = readVector3f(button.item(15).getChildNodes());
				Vector3f wallMax = readVector3f(button.item(17).getChildNodes());
				
				Vector3f button2Min = null;
				Vector3f button2Max = null;
				if(button.getLength() == 23) {
					// Has 2. Button
					button2Min = readVector3f(button.item(19).getChildNodes());
					button2Max = readVector3f(button.item(21).getChildNodes());
				}
								
				// Apply the data
				URL buttonTex = null;
				URL wallTex = null;
				try {
					buttonTex = new File(mapPath+"/"+buttonTexture).toURI().toURL();
					wallTex = new File(mapPath+"/"+wallTexture).toURI().toURL();
				} catch (MalformedURLException e1) {
					e1.printStackTrace();
				}
				
				if(button2Min == null) {
					Button bt = new Button(buttonMin, buttonMax,
							wallMin, wallMax,
							openDuration,
							hideOnCollision,
							team,
							buttonTex,wallTex);
					CollidableObjects.getInstance().addObject("gameObjects", bt);
					rootNode.attachChild(bt);
				}else{
					TwoButtons bt = new TwoButtons(buttonMin, buttonMax,
							button2Min, button2Max,
							wallMin, wallMax,
							openDuration,
							hideOnCollision,
							team,
							buttonTex,wallTex);
					CollidableObjects.getInstance().addObject("gameObjects", bt);
					rootNode.attachChild(bt);
				}
			}
		}
	}
	
	
	private static void loadElevator(Node rootNode, String mapPath, Player player) throws Exception {

		File elevatorFile = new File(mapPath+"/elevators.xml");
		if(elevatorFile.exists()) {
			Document doc = loadXMLDocument(elevatorFile);
			
			NodeList nodeList = doc.getElementsByTagName("Elevator");
			
			for(int i=0;i<nodeList.getLength();i++) {
				NodeList el = nodeList.item(i).getChildNodes();
				
				String texture = el.item(1).getFirstChild().getNodeValue();
				
				Vector3f start = readVector3f(el.item(3).getChildNodes());
				Vector3f end = readVector3f(el.item(5).getChildNodes());
				
				
				Vector3f direction = null;
				String dir = el.item(7).getFirstChild().getNodeValue();
				if(dir.equals("x")) direction = Vector3f.UNIT_X;
				else if(dir.equals("y")) direction = Vector3f.UNIT_Y;
				else if(dir.equals("z")) direction = Vector3f.UNIT_Z;
				
				
				
				float maxValue = Float.parseFloat(el.item(9).getFirstChild().getNodeValue());
				
				
				boolean activateOnCollision = false;
				if(el.item(11).getFirstChild().getNodeValue().equals("true")) {
					activateOnCollision = true;
				}
				
				
				boolean invisible = false;
				if(el.item(13).getFirstChild().getNodeValue().equals("true")) {
					invisible = true;
				}
				
				float speed = Float.parseFloat(el.item(15).getFirstChild().getNodeValue());
				
				
				
				// Apply the data
				URL textureUrl = null;
				try {
					textureUrl = new File(mapPath+"/"+texture).toURI().toURL();
				} catch (MalformedURLException e1) {
					e1.printStackTrace();
				}
				
				
				
				Vector3f extend = end.subtract(start).mult(0.5f);		
				Box elevatorBox = new Box("elevator",Vector3f.ZERO,extend.x, extend.y, extend.z);
				
				elevatorBox.setModelBound(new BoundingBox());
				elevatorBox.updateModelBound();
				
				if(texture != null) {
					elevatorBox.setRenderState(TextureCache.getInstance().getTexture(textureUrl));
				}
				elevatorBox.updateRenderState();
				
				
				Elevator elevator = 
					new Elevator(elevatorBox, direction, start.getY() + extend.getY(), maxValue, speed, activateOnCollision);
				
				elevator.setLocalTranslation(start.add(extend));
				
				if(invisible) elevator.setInvisible();
				rootNode.attachChild(elevator);
				
				PhysicsSpace.getPhysicsSpace().add(elevator);
				
				CollidableObjects.getInstance().getObjects("ground").add(elevator);
				CollidableObjects.getInstance().addObject("gameObjects", elevator);
			}
		}
	}
	
	
	private static void loadObjects(Node rootNode, String mapPath, Player player) throws Exception {
		File objFile = new File(mapPath+"/objects.xml");
		if(objFile.exists()) {
			Document doc = loadXMLDocument(objFile);
			
			Node objects = new Node("objects");
			
			NodeList nodeList = doc.getElementsByTagName("object");
			
			for(int i=0;i<nodeList.getLength();i++) {
				NodeList ground = nodeList.item(i).getChildNodes();
				
				String file = ground.item(1).getFirstChild().getNodeValue();
				
				Vector3f location = readVector3f(ground.item(3).getChildNodes());
				
				float rotation,scale;
				rotation = Float.parseFloat(ground.item(5).getFirstChild().getNodeValue());
				
				scale = Float.parseFloat(ground.item(7).getFirstChild().getNodeValue());
				
				float mass = 0;
				if(ground.getLength() == 11) {
					mass = Float.parseFloat(ground.item(9).getFirstChild().getNodeValue());
				}
				
				
				// Load Model
				try {
					Node obj = null;
					if(file.endsWith(".jme")) {
						obj = Model.loadModel(
								new File(mapPath+"/"+file).toURI().toURL(),
								Vector3f.ZERO,
								0f);
					}else if(file.endsWith(".3ds") || 
							file.endsWith(".md2") || 
							file.endsWith(".md3") || 
							file.endsWith(".ms3d") || 
							file.endsWith(".ase") || 
							file.endsWith(".obj")) {
						
						if(!ModelCache.getInstance().containsModel(mapPath+"/"+file)) {
							URL textureUrl = null;
							try {
								textureUrl = new File(mapPath+"/models").toURI().toURL();
							} catch (MalformedURLException e1) {
								e1.printStackTrace();
							}
							ModelCache.getInstance().addModel(textureUrl, textureUrl, mapPath+"/"+file);
						}
						
						BlendState bs = Game.getGame().getDisplay().getRenderer().createBlendState();
						bs.setBlendEnabled(true);
						bs.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
						bs.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
						bs.setTestEnabled(true);
						bs.setTestFunction(BlendState.TestFunction.GreaterThan);
						
						
						obj = Model.getModel("object", mapPath+"/"+file);
						obj.setRenderState(bs);
						//obj.setLocalScale(scale);
					}
					obj.setModelBound(new BoundingBox());
					obj.updateModelBound();
					
					PhysicsNode objPhysicsNode = new PhysicsNode(obj,CollisionShape.ShapeTypes.BOX, mass);
					objPhysicsNode.setLocalTranslation(location.x, location.y, location.z);
					objPhysicsNode.setLocalScale(scale);
					
					Quaternion objQuat = new Quaternion();
					objQuat.fromAngleAxis(rotation*FastMath.DEG_TO_RAD, Vector3f.UNIT_X);
					objPhysicsNode.setLocalRotation(objQuat);
					
					objects.attachChild(objPhysicsNode);

					objPhysicsNode.updateRenderState();
					// Add ground to physicsNode
			        //((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getPhyicsSpace().add(groundPhysicsNode);
					PhysicsSpace.getPhysicsSpace().add(objPhysicsNode);

			        
					
					if(mass == 0) CollidableObjects.getInstance().addObject("object", objPhysicsNode);
					else CollidableObjects.getInstance().addObject("physics", objPhysicsNode);
				} catch (MalformedURLException e) {}
			}
	        
			rootNode.attachChild(objects);
			CollidableObjects.getInstance().addObject("objNode", objects);
		}
	}
	
	
	private static void loadZombieWaypoints(Node rootNode, String mapPath, Player player) throws Exception {
		File zombieFile = new File(mapPath+"/zombieWaypoints.xml");
		if(zombieFile.exists()) {
			Document doc = loadXMLDocument(zombieFile);
			
			Vector<Waypoint> waypoints0 = new Vector<Waypoint>();
			Vector<Waypoint> waypoints1 = new Vector<Waypoint>();
			
			NodeList nodeList = doc.getElementsByTagName("Waypoint");
			
			for(int i=0;i<nodeList.getLength();i++) {
				NodeList waypoint = nodeList.item(i).getChildNodes();
				
				int zombie = Integer.parseInt(waypoint.item(1).getFirstChild().getNodeValue());
				
				Vector3f coords = readVector3f(waypoint.item(3).getChildNodes());

				Waypoint wp = new Waypoint(coords);
				if(zombie == 0) {
					for(Waypoint w:waypoints0) {
						w.addAdjazentWaypoint(wp);
					}
					waypoints0.add(wp);
				}else{
					for(Waypoint w:waypoints1) {
						w.addAdjazentWaypoint(wp);
					}
					waypoints1.add(wp);
				}
				
			}
			
			
			CaptureTheZombie ctzMode = (CaptureTheZombie)((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getGameMode();
			
			if(waypoints0.size() > 0) 
				ctzMode.getZombie(0).setStartWaypoint(waypoints0.get(0));

			if(waypoints1.size() > 0) 
				ctzMode.getZombie(1).setStartWaypoint(waypoints1.get(0));

		}
	}
	
	

	
	private static void loadVehicles(Node rootNode, String mapPath, Player player) throws Exception {
		File vehicleFile = new File(mapPath+"/vehicles.xml");
		if(vehicleFile.exists()) {
			Document doc = loadXMLDocument(vehicleFile);
			
			NodeList nodeList = doc.getElementsByTagName("Vehicle");
			
			for(int i=0;i<nodeList.getLength();i++) {
				NodeList vehicle = nodeList.item(i).getChildNodes();
				
				String type = vehicle.item(1).getFirstChild().getNodeValue().toLowerCase();
				
				Vector3f start = readVector3f(vehicle.item(3).getChildNodes());

				
				// VEHICLE-TEST
				if(type.equals("military")) {
					MilitaryCar veh = new MilitaryCar(start);
					rootNode.attachChild(veh);
				}else if(type.equals("racecar")) {
					RaceCar veh = new RaceCar(start);
					rootNode.attachChild(veh);
				}else if(type.equals("cabriocar")) {
					CabrioCar veh = new CabrioCar(start);
					rootNode.attachChild(veh);
				}
			}
		}
	}
	


	
	
	private static Vector3f readVector3f(NodeList node) {
		Vector3f vec = new Vector3f();
		
		vec.setX(Float.parseFloat(node.item(1).getFirstChild().getNodeValue()));
		vec.setY(Float.parseFloat(node.item(3).getFirstChild().getNodeValue()));
		vec.setZ(Float.parseFloat(node.item(5).getFirstChild().getNodeValue()));
		return vec;
	}

	
	
	
	private static PointLight createLight(Vector3f loc) {
		PointLight pointLight = new PointLight();
		pointLight.setLocation(loc);
		pointLight.setDiffuse(ColorRGBA.white);
		pointLight.setEnabled(true);
		
		return pointLight;
	}
}
